<?php

namespace App\Libs\DingBot;

use GuzzleHttp\Client;
use App;
use Log;
use Guzzle;

class DingBot
{
    public function send($receiver, $content, $isAll = false, $force = false)
    {
        return $this->sendText($receiver, $content, $isAll, $force);
    }


    /**
     * send text message
     * @param $receiver
     * @param $content
     * @param bool $isAll
     * @return array Guzzle Request.
     */
    public function sendText($receiver, $content, $isAll = false, $force = false)
    {
        Log::info('dingBot', [$receiver, $content]);
        list($token, $mobiles, $secret) = $this->getTokenMobilesByGroup($receiver, $force);
        if (empty($token)) {
            return [];
        }
        return $this->exec($token, $mobiles, $content, $secret, 'text', $isAll);
    }

    public function sendTextToToken($token, $content, $isAll = false)
    {
        Log::info('dingBot', [$token, $content]);
        return $this->exec($token, [], $content, 'text', $isAll);
    }


    /**
     * @param $receiver
     * @return array
     */
    protected function getTokenMobilesByGroup($receiver, $force = false)
    {
        //除生产环境和单元测试外, 钉钉消息统一发到默认机器人里.
        //生产环境如果没有找到机器人, 也发送到默认机器人里.
        $config = (App::environment('product', 'production') || $force) ? config("dingbot") : [];

        $receiver = explode('.', $receiver);
        $token = data_get($config, "{$receiver[0]}.token", env('DING_ROBOT_DEFAULT', ''));
        $secret = data_get($config, "{$receiver[0]}.secret", '');
        $mobiles = empty($receiver[1]) ? [] : data_get($config, "{$receiver[0]}.at.{$receiver[1]}", []);

        return [$token, $mobiles, $secret];
    }

    /**
     * @doc https://open-doc.dingtalk.com/docs/doc.htm?treeId=257&articleId=105735&docType=1
     * @param $token
     * @param $atMobiles
     * @param $content
     * @param string $content_type
     * @param bool $isAll
     * @return array
     */
    public function exec($token, $atMobiles, $content, $secret, $content_type = 'text', $isAll = false)
    {
        list($s1, $s2) = explode(' ', microtime());

        $timestamp = (float)sprintf('%.0f', (floatval($s1) + floatval($s2)) * 1000);
        $sign = $this->sign($timestamp, $secret);
        $request = [
            'uri' => "https://oapi.dingtalk.com/robot/send?access_token=" . $token."&timestamp=$timestamp&sign=".$sign,
            'options' => [
                'json' => [
                    'msgtype' => $content_type,
                    'at' => [
                        "atMobiles" => $atMobiles,
                        "isAtAll" => $isAll,
                    ],
                ],
                'timeout' => 1,
                'http_errors' => false
            ],
        ];

        switch ($content_type) {
            case 'link':
            case 'markdown':
                $request['options']['json'][$content_type] = $content;
                break;
            case 'text':
                $request['options']['json']['text'] = ['content' => $content];
                break;
        }

        if (!App::environment('testing')) {
            $response = Guzzle::post($request['uri'], $request['options']);
            $responseBody = json_decode($response->getBody()->getContents(), true);
            if (data_get($responseBody, 'errcode'))
                Log::error('dingtalk robot error', ['response' => $responseBody, 'request' => $request]);
        }

        return $request;
    }

    public function sign($timestamp, $secret)
    {
        $data = $timestamp . "\n" . $secret;

        $signStr = base64_encode(hash_hmac('sha256', $data, $secret,true));

        $signStr = utf8_encode(urlencode($signStr));

        return $signStr;
    }
}
